<template>
	<view class="v-pull-up-refresh" :style="{ height: containerHeight }">
		<view class="pull-up-refresh-header" v-if="pullingDown || refreshing">
			<slot name="pull-up-refresh" :pullingDown="pullingDown" :refreshing="refreshing">
				<view class="pull-up-refresh-header-icon">
					<view v-if="!refreshing" class="arrow-down"></view>
					<v-min-loading v-model:value="refreshing" type="info"></v-min-loading>
				</view>
				<text>{{ pullingDown ? '释放刷新' : refreshing ? '正在刷新...' : '下拉刷新' }}</text>
			</slot>
		</view>
		<view class="pull-up-refresh-content" :style="{ transform: `translateY(${translateY}px)` }">
			<slot></slot>
		</view>
	</view>
</template>

<script lang="ts" setup>
import { ref, onMounted, onUnmounted, nextTick, inject } from 'vue';

/**
 * v-pull-up-refresh	上拉刷新
 *
 */
const props = defineProps({
	refreshHeight: {
		type: Number,
		default: 60
	}
});

const emits = defineEmits(['refresh']);

const config = inject<any>('config');
const containerHeight = ref('100%');
const translateY = ref(0);
const pullingDown = ref(false);
const refreshing = ref(false);

let startY = 0;
let moveY = 0;
let moveDistance = 0;

const handleTouchStart = (event: TouchEvent) => {
	startY = event.touches[0].pageY;
};

const handleTouchMove = (event: TouchEvent) => {
	if (refreshing.value) return;

	moveY = event.touches[0].pageY;
	moveDistance = moveY - startY;

	if (moveDistance > 0) {
		pullingDown.value = true;
		translateY.value = moveDistance;
	}
};

const handleTouchEnd = () => {
	if (refreshing.value) return;

	if (pullingDown.value && moveDistance > props.refreshHeight) {
		startRefresh();
	} else {
		translateY.value = 0;
		pullingDown.value = false;
	}
};

const startRefresh = () => {
	refreshing.value = true;
	pullingDown.value = false;
	translateY.value = props.refreshHeight;

	emits('refresh', () => {
		endRefresh();
	});
};

const endRefresh = () => {
	refreshing.value = false;
	translateY.value = 0;
	nextTick(() => {
		translateY.value = 0;
	});
};

onMounted(() => {
	const container = document.querySelector('.v-pull-up-refresh');
	if (container) {
		container.addEventListener('touchstart', handleTouchStart);
		container.addEventListener('touchmove', handleTouchMove);
		container.addEventListener('touchend', handleTouchEnd);
	}
});

onUnmounted(() => {
	const container = document.querySelector('.v-pull-up-refresh');
	if (container) {
		container.removeEventListener('touchstart', handleTouchStart);
		container.removeEventListener('touchmove', handleTouchMove);
		container.removeEventListener('touchend', handleTouchEnd);
	}
});
</script>

<style lang="scss" scoped>
.v-pull-up-refresh {
	position: relative;
	overflow: hidden;
}

.pull-up-refresh-content {
	transition: transform 0.3s ease;
}

.pull-up-refresh-header {
	display: flex;
	align-items: center;
	justify-content: center;
	height: 120rpx;
	background-color: v-bind("config.backgroundColor.reversal");
	color:  v-bind("config.fontColor.mainText");
	font-size: 14px;
}

.pull-up-refresh-header-icon {
	margin-right: 16rpx;
}

.arrow-down {
	width: 0;
	height: 0;
	border: 5rpx solid transparent;
	border-bottom-color: v-bind("config.fontColor.mainText");
	transition: transform 0.3s ease;
}

.spinner {
	width: 20px;
	height: 20px;
	border: 2px solid v-bind("config.border.color");
	border-top-color: transparent;
	border-radius: 50%;
	animation: spin 1s linear infinite;
}

@keyframes spin {
	from {
		transform: rotate(0deg);
	}
	to {
		transform: rotate(360deg);
	}
}
</style>
